import "dart:io";

import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart' show rootBundle;
import 'package:flutter_chat_ui/utils/performance_monitor.dart';
import 'package:flutter_chat_ui/utils/x_toast.dart';
import 'package:logger/web.dart';
import 'package:path/path.dart';
import 'package:path_provider/path_provider.dart';
import 'package:sherpa_onnx/sherpa_onnx.dart';

class LLMUtils with LLMUtilsCommon, LLMUtilsRecognizerMixin {
  /// 私有构造函数 - 防止外部实例化
  LLMUtils._internal();
  static final LLMUtils _instance = LLMUtils._internal();

  /// 使用方式：第一种 => 工厂构造函数 - 返回唯一的实例
  /// 使用方式：LLMUtils utils = LLMUtils();
  factory LLMUtils() => _instance;

  /// 使用方式：第二种 => 获取单例实例的静态方法（可选）
  /// 使用方式：LLMUtils utils = LLMUtils.instance;
  static LLMUtils get instance => _instance;

  /// sherpa_onnx所需属性
  OnlineRecognizer? recognizer; // 语音识别器实例
  OnlineStream? speechStream; // 语音流实例
  KeywordSpotter? keywordSpotter; // 关键词识别器实例

  /// 初始化状态
  bool _isInitialized = false;
  bool _isInitializing = false;

  /// 获取初始化状态
  bool get isInitialized => _isInitialized;
  bool get isInitializing => _isInitializing;

  /// 预初始化语音识别器，支持UI更新回调
  Future<void> preInitializeSST() async {
    return await PerformanceMonitor.measureAsync('语音识别器初始化', () async {
      // 如果已经初始化或正在初始化，直接返回
      if (_isInitialized || _isInitializing) {
        return;
      }

      _isInitializing = true;

      try {
        // 步骤1: 初始化绑定
        await PerformanceMonitor.measureAsync('初始化绑定', () async {
          initBindings();
        });

        // 步骤2: 创建识别器（这是最耗时的操作）
        recognizer = await createOnlineRecognizer();

        // 步骤3: 创建音频流
        await PerformanceMonitor.measureAsync('创建音频流', () async {
          speechStream = recognizer?.createStream();
        });

        _isInitialized = true;
      } catch (e) {
        _isInitialized = false;
        final errorMsg = '预初始化语音识别器失败: $e';
        XToast.showError(errorMsg, duration: const Duration(seconds: 5));
        throw Exception('Pre-initialization failed: $e');
      } finally {
        _isInitializing = false;
      }
    });
  }

  /// 将字节数组转换为Float32浮点数组
  ///
  /// [bytes] 输入的字节数组，通常包含16位整数音频数据
  ///
  /// [endian] 字节序，默认为小端序（Endian.little）
  ///
  /// 返回Float32List，包含归一化后的浮点数值（范围-1.0到1.0）
  ///
  Float32List convertBytesToFloat32(Uint8List bytes, [endian = Endian.little]) {
    // 创建Float32数组，长度为输入字节数组的一半（因为每个Float32由2个字节组成）
    final values = Float32List(bytes.length ~/ 2);

    // 创建ByteData视图，用于按不同字节序读取数据
    final data = ByteData.view(bytes.buffer);

    // 遍历字节数组，每次处理2个字节
    for (var i = 0; i < bytes.length; i += 2) {
      // 从当前位置读取16位有符号整数（short类型）
      int short = data.getInt16(i, endian);

      // 将16位整数归一化为-1.0到1.0之间的浮点数
      // 32768.0是16位有符号整数的最大值（2^15 - 1），用于归一化
      values[i ~/ 2] = short / 32768.0;
    }

    // 返回转换后的浮点数组
    return values;
  }

  ///
  /// 销毁
  ///
  void dispose() {
    recognizer?.reset(speechStream!);
    speechStream?.free();
    recognizer?.free();
    speechStream = null;
    recognizer = null;
    _isInitialized = false;
    _isInitializing = false;
  }
}

///
/// 语音识别工具
///
mixin LLMUtilsRecognizerMixin on LLMUtilsCommon {
  ///
  /// 创建语音识别器，支持UI更新回调
  ///
  Future<OnlineRecognizer> createOnlineRecognizer() async {
    return await PerformanceMonitor.measureAsync('创建识别器', () async {
      try {
        // 步骤1: 获取模型配置
        final modelConfig = await getOnlineRecognizerModelConfig();

        // 步骤2: 创建配置对象
        final config = OnlineRecognizerConfig(
          model: modelConfig,
          ruleFsts: '',
        );

        // 步骤3: 实例化识别器 - 这是最耗时的操作
        return await PerformanceMonitor.measureAsync('实例化识别器', () async {
          // 分批次创建，避免长时间阻塞
          OnlineRecognizer? recognizer;

          // 使用Future.microtask分解操作
          await Future.microtask(() {
            recognizer = OnlineRecognizer(config);
          });

          return recognizer!;
        });
      } catch (e) {
        throw Exception('Failed to create OnlineRecognizer: $e');
      }
    });
  }

  ///
  /// 获取在线模型配置【目前使用模型：sherpa-onnx-streaming-zipformer-bilingual-zh-en-2023-02-20】
  /// 下载地址：https://github.com/k2-fsa/sherpa-onnx/releases/tag/asr-models
  ///
  /// 获取在线模型配置，支持UI更新回调
  ///
  Future<OnlineModelConfig> getOnlineRecognizerModelConfig() async {
    return await PerformanceMonitor.measureAsync('加载模型配置', () async {
      const modelDir = 'assets/llm/sherpa-onnx-streaming-zipformer-bilingual-zh-en-2023-02-20';

      // 定义文件路径和名称映射
      final fileMap = {
        'encoder': '$modelDir/encoder-epoch-99-avg-1.int8.onnx',
        'decoder': '$modelDir/decoder-epoch-99-avg-1.onnx',
        'joiner': '$modelDir/joiner-epoch-99-avg-1.onnx',
        'tokens': '$modelDir/tokens.txt',
      };

      // 逐个复制文件，每次复制后让出控制权
      final results = <String>[];

      for (final entry in fileMap.entries) {
        final result = await copyAssetFile(entry.value);
        results.add(result);
      }

      return OnlineModelConfig(
        transducer: OnlineTransducerModelConfig(
          encoder: results[0],
          decoder: results[1],
          joiner: results[2],
        ),
        tokens: results[3],
        modelType: 'zipformer',
      );
    });
  }
}

///
/// 唤醒词工具
///
mixin LLMUtilsWksMixin {}

///
/// 公共工具
///
mixin LLMUtilsCommon {
  String kStreamSSTDirName = "StreamSST"; // sst文件夹名

  // 缓存目录路径，避免重复获取
  static Directory? _cachedDirectory;
  static Directory? _cachedStreamSSTDir;

  /// 将资源文件从assets目录复制到应用文档目录，支持UI更新回调
  ///
  /// [src] 源文件在assets中的路径，例如 'assets/models/model.onnx'
  /// [yieldToUI] UI更新回调函数
  ///
  /// 返回复制后的文件完整路径
  ///
  Future<String> copyAssetFile(String src) async {
    return await PerformanceMonitor.measureAsync('复制文件: ${basename(src)}', () async {
      // 使用缓存的目录路径，避免重复获取
      _cachedDirectory ??= await getApplicationDocumentsDirectory();

      // 创建StreamSST文件夹路径（使用缓存）
      _cachedStreamSSTDir ??= Directory(join(_cachedDirectory!.path, kStreamSSTDirName));

      // 确保文件夹存在，如果不存在则创建（只需要创建一次）
      if (!await _cachedStreamSSTDir!.exists()) {
        await _cachedStreamSSTDir!.create(recursive: true);
      }

      // 构建完整的文件路径：文档目录 + 目标文件名
      final target = join(_cachedStreamSSTDir!.path, basename(src));
      final targetFile = File(target);

      // 检查目标文件是否已存在
      if (await targetFile.exists()) {
        // 文件已存在，直接返回路径，避免重复复制
        Logger().i('📁 文件已存在，跳过复制: ${basename(src)}');
        Logger().i('📁 文件已存在路径: $target');
        return target;
      }

      try {
        // 使用compute在独立isolate中加载文件，避免阻塞UI
        final bytes = await compute(_loadAssetFileInIsolate, src);

        // 将字节数组写入目标文件
        await targetFile.writeAsBytes(bytes);

        Logger().i('📁 文件复制完成: ${basename(src)} (${(bytes.length / 1024 / 1024).toStringAsFixed(2)} MB)');

        // 返回最终文件的完整路径
        return target;
      } catch (e) {
        // 如果compute失败，回退到主线程处理
        Logger().w('Isolate加载失败，回退到主线程: $e');

        // 从assets中加载源文件数据
        final data = await rootBundle.load(src);

        // 将加载的数据转换为字节数组
        final List<int> bytes = data.buffer.asUint8List(data.offsetInBytes, data.lengthInBytes);

        // 将字节数组写入目标文件
        await targetFile.writeAsBytes(bytes);

        Logger().i('📁 文件复制完成: ${basename(src)} (${(bytes.length / 1024 / 1024).toStringAsFixed(2)} MB)');

        // 返回最终文件的完整路径
        return target;
      }
    });
  }

  /// 在独立isolate中加载asset文件
  static Future<List<int>> _loadAssetFileInIsolate(String src) async {
    try {
      final data = await rootBundle.load(src);
      return data.buffer.asUint8List(data.offsetInBytes, data.lengthInBytes);
    } catch (e) {
      throw Exception('Failed to load asset file in isolate: $e');
    }
  }
}
